import com.fasterxml.jackson.module.kotlin.jacksonObjectMapper
import com.fasterxml.jackson.module.kotlin.readValue
import java.io.File
import java.sql.Connection
import java.sql.DriverManager

fun main() {
    val tableNames: List<String> = listOf(
        "scheme_knowledge_base",
        "scheme_org",
        "scheme_person",
        "scheme_product",
        "scheme_trial",
        "scheme_endpoint",
        "scheme_sample_size_calc_param",
        "scheme_reference_literature",
        "scheme_reference_literature_file",
        "scheme_subject_standard"
    )

    tableNames.forEach { tableName ->
        val javaSourceCode = generateJavaClassSourceCode(tableName)
        writeFile(underscoreToPascalCase(tableName) + ".java", javaSourceCode)
    }
}

/**
 * 写文件
 */
fun writeFile(tableName: String, javaSourceCode: String) {
    File(tableName).writeText(javaSourceCode)
}

/**
 * 根据MySQL表名生成Java类文件
 */
fun generateJavaClassSourceCode(tableName: String): String {

    var tableComment = ""
    getConnection().use {
        val sql = """
            SELECT TABLE_NAME AS tableName, TABLE_COMMENT AS tableComment
             FROM information_schema.tables WHERE TABLE_NAME = '$tableName'
        """.trimIndent()

        val statement = it.prepareStatement(sql)
        val resultSet = statement.executeQuery()
        while (resultSet.next()) {
            tableComment = resultSet.getString("tableComment")
        }
    }

    val javaStatements: List<String> = mutableListOf()
    getConnection().use {
        val sql = """
            SELECT COLUMN_NAME AS columnName, DATA_TYPE AS dataType, COLUMN_COMMENT AS columnComment
             FROM information_schema.columns 
             WHERE TABLE_NAME = '$tableName' ORDER BY ORDINAL_POSITION
        """.trimIndent()
        val statement = it.prepareStatement(sql)
        val resultSet = statement.executeQuery()

        while (resultSet.next()) {
            val columnName = resultSet.getString("columnName")
            val camelCaseColumnName = underscoreToCamelCase(columnName)
            val dataType = resultSet.getString("dataType")
            val columnComment = resultSet.getString("columnComment")

            val javaType: String = getJavaTypeBySqlDataType(dataType)
            val javaStatement: String = """
                
                /**
                 * $columnComment
                 */
                private $javaType $camelCaseColumnName;
            """.trimIndent()

            javaStatements.addLast(javaStatement)
        }
    }

    val javaClassName: String = underscoreToPascalCase(tableName)
    var javaSourceCode = """
        package com.medinc.rdmp.common.domain.schema;
        
        import com.baomidou.mybatisplus.annotation.TableName;
        import lombok.Data;
        
        import java.time.OffsetDateTime;
        
        /**
         * $tableComment
         */
        @Data
        @TableName("$tableName")
        public class $javaClassName {
        
    """.trimIndent()
    javaSourceCode += javaStatements.joinToString(separator = "")
    javaSourceCode += """
        
        }
    """.trimIndent()

    println(javaSourceCode)
    return javaSourceCode
}

/**
 * 根据SQL类型返回JAVA类型
 */
fun getJavaTypeBySqlDataType(dataType: String?): String {
    val javaType = when (dataType) {
        "tinyint", "int" -> "Integer"
        "varchar", "json" -> "String"
        "date" -> "LocalDate"
        "datetime" -> "OffsetDateTime"
        else -> ""
    }
    return javaType
}

/**
 * 下划线转Pascal
 */
fun underscoreToPascalCase(field: String): String {
    val splitArray = field.split("_")
    if (splitArray.isEmpty()) {
        return ""
    }
    val restUpperWords = splitArray.joinToString(separator = "") { it ->
        it.replaceFirstChar { it.uppercase() }
    }
    return restUpperWords
}

/**
 * 下划线转驼峰
 */
fun underscoreToCamelCase(field: String): String {
    val splitArray = field.split("_")
    if (splitArray.isEmpty()) {
        return ""
    }
    val firstWord = splitArray[0]
    val restUpperWords = splitArray.takeLast(splitArray.size - 1).joinToString(separator = "") { it ->
        it.replaceFirstChar { it.uppercase() }
    }
    return firstWord + restUpperWords
}

/**
 * 获取SQL连接
 */
fun getConnection(): Connection {
    val dbPropertyJson = object {}.javaClass.getResourceAsStream("db.json")?.bufferedReader()?.readText()
    if (dbPropertyJson.isNullOrEmpty()) {
        throw RuntimeException("db.json is null")
    }

    val mapper = jacksonObjectMapper()

    val dbProperty: DbProperty = mapper.readValue(dbPropertyJson)

    return DriverManager.getConnection(dbProperty.url, dbProperty.username, dbProperty.password)
}

